﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using AMM.Model;
using AMM.Model.Business;

namespace AMM.DataAccess.Business {
    public class ProduceConductRepository : BaseRepository<ProduceConduct> {

        private int _pageSize;

        public ProduceConductRepository(int pageSize = int.MaxValue) {
            this._pageSize = pageSize;
        }

        public ProduceConduct FetchProduceConductById(int produceConductId) {
            using (var ctx = this.Context) {
                return ctx.ProduceConducts.Find(produceConductId);
            }
        }

        public ProduceConduct FetchProduceConductByIdForPrint(int produceConductId) {
            using (var ctx = this.Context) {
                return ctx.ProduceConducts
                    .Include("Basic")
                    .Include("Product")
                    .Include("Product.Basic1")
                    .Include("CustomerOrder")
                    .FirstOrDefault(x => x.ProduceConductId == produceConductId);
            }
        }

        public List<ProduceConduct> FetchProduceConductByCustomerOrderId(int customerOrderId) {
            using (var ctx = this.Context) {
                return ctx.ProduceConducts
                    //.Include("Basic")
                    //.Include("CustomerOrder")
                    //.Include("Product")
                    .Where(x => x.CustomerOrderId == customerOrderId)
                    .ToList();
            }
        }

        public void UpdateProduceConduct(List<ProduceConduct> produceConductList) {
            using (var ctx = this.Context) {
                using (DbContextTransaction trans = ctx.Database.BeginTransaction()) {
                    try {
                        produceConductList.ForEach(x => {
                            switch (x.ClassStatus) {
                                case ClassStatus.UnChanged:
                                    ctx.ProduceConducts.Attach(x);
                                    ctx.Entry(x).State = EntityState.Unchanged;
                                    break;
                                case ClassStatus.Updated:
                                    x.ModifiedDatetime = DateTime.Now;
                                    ctx.ProduceConducts.Attach(x);
                                    ctx.Entry(x).State = EntityState.Modified;
                                    break;
                                case ClassStatus.Added:
                                    x.CreatedDatetime = DateTime.Now;
                                    ctx.ProduceConducts.Attach(x);
                                    ctx.Entry(x).State = EntityState.Added;
                                    break;
                                case ClassStatus.Deleted:
                                    ctx.ProduceConducts.Attach(x);
                                    ctx.Entry(x).State = EntityState.Deleted;
                                    break;
                            }
                        });

                        ctx.SaveChanges();
                        trans.Commit();
                    }
                    catch (Exception ex) {
                        trans.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void DeleteMultipleProduceConduct(params int[] produceConductIds) {
            using (var ctx = this.Context) {
                using (DbContextTransaction trans = ctx.Database.BeginTransaction()) {
                    try {
                        ctx.ProduceConducts.Where(x => produceConductIds.Contains(x.ProduceConductId)).ToList().ForEach(x => {
                            ctx.ProduceConducts.Remove(x);
                        });
                        ctx.ProduceConducts.Where(x => produceConductIds.Contains(x.ProduceConductId)).ToList().ForEach(x => {
                            ctx.ProduceConducts.Remove(x);
                        });
                        ctx.SaveChanges();
                        trans.Commit();
                    }
                    catch (Exception ex) {
                        trans.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public int GetTheMaxFlowNumber(string startString) {
            using (var ctx = this.Context) {
                ProduceConduct produceConduct = ctx.ProduceConducts
                    .Where(x => x.Code.StartsWith(startString))
                    .OrderByDescending(x => x.Code)
                    .FirstOrDefault();
                int maxFlowNumber = produceConduct == null
                    ? 0
                    : Convert.ToInt32(produceConduct.Code.Substring(produceConduct.Code.Length - 2, 2));
                return Math.Max(ctx.ProduceConducts.Count(x => x.Code.StartsWith(startString)), maxFlowNumber);
            }
        }

        public List<ProduceConduct> FetchProduceConductList(ProduceConductSearchModel searchModel, int pageIndex) {
            using (var ctx = this.Context) {
                var query = ctx.ProduceConducts
                    .Include("Basic")
                    .Include("CustomerOrder")
                    .Include("Product")
                    .Include("ProcurementOrder")
                    .Where(x => !string.IsNullOrEmpty(x.Code));

                if (searchModel.OrderDateStart.HasValue) {
                    query = query.Where(x => x.OrderDate >= DbFunctions.TruncateTime(searchModel.OrderDateStart.Value));
                }
                if (searchModel.OrderDateEnd.HasValue) {
                    query = query.Where(x => x.OrderDate <= DbFunctions.TruncateTime(searchModel.OrderDateEnd.Value));
                }
                if (searchModel.CustomerOrderId.HasValue) {
                    query = query.Where(x => x.CustomerOrderId == searchModel.CustomerOrderId.Value);
                }
                if (searchModel.ProduceConductTypeId.HasValue) {
                    query = query.Where(x => x.Basic.BasicsId == searchModel.ProduceConductTypeId.Value);
                }
                if (searchModel.IsLocked) {
                    query = query.Where(x => x.IsLocked == searchModel.IsLocked);
                }

                searchModel.Records = query.Count();
                pageIndex = (pageIndex - 1) * this._pageSize > searchModel.Records ? 1 : pageIndex;

                return query.OrderByDescending(x => x.CreatedDatetime).Skip((pageIndex - 1) * this._pageSize).Take(this._pageSize).ToList();
            }
        }

        public List<BOMDetail> FetchProduceConductBOMMaterialList(int produceConductId) {
            using (var ctx = this.Context) {
                var query = from a in ctx.ProduceConducts
                            join b in ctx.Products on a.ProductId equals b.ProductId
                            join c in ctx.BOMs.Where(x => x.BOMStatus == 2) on b.Code equals c.Code into cOutput
                            from c1 in cOutput.DefaultIfEmpty()
                            join d in ctx.BOMDetails on c1.BOMId equals d.BOMId into dOutput
                            from d1 in dOutput.DefaultIfEmpty()
                            where a.ProduceConductId == produceConductId
                            select d1;

                var query1 = from a in ctx.BOMDetails
                             join b in ctx.BOMs.Where(x => x.BOMStatus == 2) on a.BOMId equals b.BOMId
                             join c in ctx.Products on b.Code equals c.Code
                             join d in ctx.ProduceConducts on c.ProductId equals d.ProductId
                             where d.ProduceConductId == produceConductId
                             select a;

                return query
                    .Include("Basic")
                    .Include("Material")
                    .Include("Material.Basic")
                    .Where(x => x != null)
                    .ToList();
            }
        }

        public List<OutStoreOrderDetail> FetchProduceConductMaterialList(int produceConductId) {
            using (var ctx = this.Context) {
                var query = from a in ctx.ProduceConducts
                            join b in ctx.Products on a.ProductId equals b.ProductId
                            join c in ctx.BOMs.Where(x => x.BOMStatus == 2) on b.Code equals c.Code into cOutput
                            from c1 in cOutput.DefaultIfEmpty()
                            join d in ctx.BOMDetails on c1.BOMId equals d.BOMId into dOutput
                            from d1 in dOutput.DefaultIfEmpty()
                            where a.ProduceConductId == produceConductId
                            select new {
                                MaterialId = d1.MaterialId,
                                Quantity = a.BatchAmount * d1.SingleCosts,
                                StoreQuantity = 0,
                                ErrMessage = string.Empty
                            };

                List<OutStoreOrderDetail> resultList = new List<OutStoreOrderDetail>();
                query.ToList().ForEach(x => {
                    List<MaterialStore> msList = ctx.MaterialStores.Where(y => y.MaterialId == x.MaterialId).ToList();
                    resultList.Add(new OutStoreOrderDetail() {
                        MaterialId = x.MaterialId,
                        Quantity = x.Quantity,
                        StoreQuantity = msList.Count == 0 ? 0m : msList.Sum(y => y.Quantity)
                    });
                });

                return resultList;
            }
        }
    }
}
